/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#ifndef INCLUDE_SHADER_NOISE
#define INCLUDE_SHADER_NOISE

#include "shader_built_in_functions.h"


#ifdef __cplusplus

#include <向量.h>

// GLSL Type
using uint = unsigned int;
#define in
#define out
#define inout



Inline float f_glsl_simplexNoise(const vec2& uv) {
	//const float K1 = 0.366025404; // (sqrt(3)-1)/2;
	//const float K2 = 0.211324865; // (3 - sqrt(3))/6;
	//
	//vec3 quadIntPos = floor(uv + (uv.x + uv.y + uv.z) * K1);
	//vec3 vecFromA = uv - quadIntPos + (quadIntPos.x + quadIntPos.y + quadIntPos.z) * K2;
	//vec3 IsLeftHalf = step(yzx(vecFromA), vecFromA);
	//vec3 quadVertexOffset = (IsLeftHalf * yzx(IsLeftHalf));
	//
	//vec3 vecFromB = vecFromA - quadVertexOffset + K2;
	//vec3 vecFromC = vecFromA - 1.0 + 2.0 * K2;
	//
	//vec4 dxyz;
	//dxyz.x = dot(vecFromA, vecFromA);
	//dxyz.y = dot(vecFromB, vecFromB);
	//dxyz.z = dot(vecFromC, vecFromC);
	//dxyz.w = dot(vecFromA + 0.5 - quadIntPos * K1, vecFromA + 0.5 - quadIntPos * K1);
	//
	//vec4 falloff;
	//falloff.x = 0.5 - dxyz.x;
	//falloff.y = 0.5 - dxyz.y;
	//falloff.z = 0.5 - dxyz.z;
	//falloff.w = 0.5 - dxyz.w;
	//
	//vec4 Zero{};
	//falloff = max(falloff, Zero);
	//
	//vec3 ga = random(quadIntPos + 0.0);
	//vec3 gb = random(quadIntPos + quadVertexOffset);
	//vec3 gc = random(quadIntPos + 1.0);
	//
	//vec4 gradient;
	//gradient.x = dot(vecFromA, ga);
	//gradient.y = dot(vecFromB, gb);
	//gradient.z = dot(vecFromC, gc);
	//gradient.w = dot(vecFromA - quadVertexOffset, ga) * falloff.w;
	//
	//vec4 n = normalize(falloff * falloff * falloff * falloff * gradient);
	////blend all vertices' contribution
	//vec4 w;
	//w.x = 1.1;
	//w.y = 1.3;
	//w.z = 1.5;
	//w.w = 1.7;
	//return (dot((n), normalize(w)));



	const float K1 = 0.366025404;
	const float K2 = 0.211324865;

	vec2 quadIntPos = floor(uv + (uv.x + uv.y) * K1);
	vec2 vecFromA = uv - quadIntPos + (quadIntPos.x + quadIntPos.y) * K2;
	float IsLeftHalf = step(vecFromA.y, vecFromA.x);
	vec2 quadVertexOffset = vec2{IsLeftHalf, (1 - IsLeftHalf)};

	vec2 vecFromB = vecFromA - quadVertexOffset + K2;
	vec2 vecFromC = vecFromA - 1.0 + 2.0 * K2;

	vec3 dxyz;
	dxyz.x = dot(vecFromA, vecFromA);
	dxyz.y = dot(vecFromB, vecFromB);
	dxyz.z = dot(vecFromC, vecFromC);

	vec3 falloff;
	falloff.x = 0.5 - dxyz.x;
	falloff.y = 0.5 - dxyz.y;
	falloff.z = 0.5 - dxyz.z;

	//vec4 Zero = vec4(0);
	falloff = max(falloff, vec3{0});

	vec2 ga = random(quadIntPos + 0.0);
	vec2 gb = random(quadIntPos + quadVertexOffset);
	vec2 gc = random(quadIntPos + 1.0);

	vec3 gradient;
	gradient.x = dot(vecFromA, ga);
	gradient.y = dot(vecFromB, gb);
	gradient.z = dot(vecFromC, gc);

	vec3 n = (falloff * falloff * falloff * falloff * gradient);
	//blend all vertices' contribution
	vec3 w;
	w.x = 60.0;
	w.y = 60.0;
	w.z = 60.0;
	return dot(n, w);
}



#else

#define Inline


float f_glsl_simplexNoise(in vec3 uv) {
	//const float K1 = 0.366025404;
	//const float K2 = 0.211324865;
	//
	//vec3 quadIntPos = floor(uv + (uv.x + uv.y + uv.z) * K1);
	//vec3 vecFromA = uv - quadIntPos + (quadIntPos.x + quadIntPos.y + quadIntPos.z) * K2;
	//vec3 IsLeftHalf = step(vecFromA.yzx, vecFromA);
	//vec3 quadVertexOffset = IsLeftHalf * (IsLeftHalf.yzx);
	//
	//vec3 vecFromB = vecFromA - quadVertexOffset + K2;
	//vec3 vecFromC = vecFromA - 1.0 + 2.0 * K2;
	//
	//vec4 dxyz;
	//dxyz.x = dot(vecFromA, vecFromA);
	//dxyz.y = dot(vecFromB, vecFromB);
	//dxyz.z = dot(vecFromC, vecFromC);
	//dxyz.w = dot(vecFromA + 0.5 - quadIntPos * K1, vecFromA + 0.5 - quadIntPos * K1);
	//
	//vec4 falloff;
	//falloff.x = 0.5 - dxyz.x;
	//falloff.y = 0.5 - dxyz.y;
	//falloff.z = 0.5 - dxyz.z;
	//falloff.w = 0.5 - dxyz.w;
	//
	//vec4 Zero = vec4(0);
	//falloff = max(falloff, vec4(0));
	//
	//vec3 ga = random(quadIntPos + 0.0);
	//vec3 gb = random(quadIntPos + quadVertexOffset);
	//vec3 gc = random(quadIntPos + 1.0);
	//
	//vec4 gradient;
	//gradient.x = dot(vecFromA, ga);
	//gradient.y = dot(vecFromB, gb);
	//gradient.z = dot(vecFromC, gc);
	//gradient.z = dot(vecFromA - quadVertexOffset, ga) * falloff.w;
	//
	//vec4 n = normalize(falloff * falloff * falloff * falloff * gradient);
	////blend all vertices' contribution
	//vec4 w;
	//w.x = 51.1;
	//w.y = 51.3;
	//w.z = 51.5;
	//w.w = 51.7;
	//return dot(n, normalize(w) );



	const float K1 = 0.366025404;
	const float K2 = 0.211324865;

	vec2 quadIntPos = floor(uv.xy + (uv.x + uv.y) * K1);
	vec2 vecFromA = uv.xy - quadIntPos + (quadIntPos.x + quadIntPos.y) * K2;
	float IsLeftHalf = step(vecFromA.y, vecFromA.x);
	vec2 quadVertexOffset = vec2(IsLeftHalf, (1-IsLeftHalf));

	vec2 vecFromB = vecFromA - quadVertexOffset + K2;
	vec2 vecFromC = vecFromA - 1.0 + 2.0 * K2;

	vec3 dxyz;
	dxyz.x = dot(vecFromA, vecFromA);
	dxyz.y = dot(vecFromB, vecFromB);
	dxyz.z = dot(vecFromC, vecFromC);

	vec3 falloff;
	falloff.x = 0.5 - dxyz.x;
	falloff.y = 0.5 - dxyz.y;
	falloff.z = 0.5 - dxyz.z;

	//vec4 Zero = vec4(0);
	falloff = max(falloff, vec3(0));

	vec2 ga = random(quadIntPos + 0.0);
	vec2 gb = random(quadIntPos + quadVertexOffset);
	vec2 gc = random(quadIntPos + 1.0);

	vec3 gradient;
	gradient.x = dot(vecFromA, ga);
	gradient.y = dot(vecFromB, gb);
	gradient.z = dot(vecFromC, gc);

	vec3 n = (falloff * falloff * falloff * falloff * gradient);
	//blend all vertices' contribution
	vec3 w;
	w.x = 60.0;
	w.y = 60.0;
	w.z = 60.0;
	return dot(n, w);
}



#endif




//Inline float f_glsl_simplexNoise(in vec2 uv) {
//	//transform from triangle to quad
//	const float K1 = 0.366025404; // (sqrt(3)-1)/2;
//	//transform from quad to triangle
//	const float K2 = 0.211324865; // (3 - sqrt(3))/6;
//
//	//Find the rectangle vertex
//	vec2  quadIntPos = floor(uv + (uv.x + uv.y) * K1);
//	//relative coorindates from origin vertex A
//	vec2  vecFromA = uv - quadIntPos + (quadIntPos.x + quadIntPos.y) * K2;
//	float IsLeftHalf = step(vecFromA.y, vecFromA.x);
//	vec2  quadVertexOffset;
//	quadVertexOffset.x = IsLeftHalf;
//	quadVertexOffset.y = 1.0f - IsLeftHalf;
//
//	//vecFromA - (quadVertexOffset + (quadVertexOffset.x + quadVertexOffset.y ) * K2)
//	vec2  vecFromB = vecFromA - quadVertexOffset + K2;
//	//vecFromA - (vec(1, 1) + (1 + 1 ) * K2)
//	vec2  vecFromC = vecFromA - 1.0 + 2.0 * K2;
//
//	vec3 dxyz;
//	dxyz.x = dot(vecFromA, vecFromA);
//	dxyz.y = dot(vecFromB, vecFromB);
//	dxyz.z = dot(vecFromC, vecFromC);
//
//	vec3  falloff;
//	falloff.x = 0.5 - dxyz.x;
//	falloff.y = 0.5 - dxyz.y;
//	falloff.z = 0.5 - dxyz.z;
//
//	vec3 Zero;
//	Zero.x = 0;
//	Zero.y = 0;
//	Zero.z = 0;
//	falloff = max(falloff, Zero);
//
//	vec2 ga = random(quadIntPos + 0.0);
//	vec2 gb = random(quadIntPos + quadVertexOffset);
//	vec2 gc = random(quadIntPos + 1.0);
//
//	vec3 gradient;
//	gradient.x = dot(vecFromA, ga);
//	gradient.y = dot(vecFromB, gb);
//	gradient.z = dot(vecFromC, gc);
//	
//	vec3 n = falloff * falloff * falloff * falloff * gradient;
//	//blend all vertices' contribution
//	vec3 w;
//	w.x = 50.1;
//	w.y = 50.1;
//	w.z = 50.7;
//	return dot(n, w);
//}


Inline vec3 f_perlin2DNoise(in vec2 uv, bool revert) {
	vec2 i = floor(uv);
	vec2 f = fract(uv);


	// quintic interpolation
	vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);
	vec2 du = f * f * 30.0f * (f * (f - 2.0) + 1.0);

	vec2 a; a.x = 0; a.y = 0;
	vec2 b; b.x = 1; b.y = 0;
	vec2 c; c.x = 0; c.y = 1;
	vec2 d; d.x = 1; d.y = 1;
	//random gradients
	vec2 ga = random(i + a);
	vec2 gb = random(i + b);
	vec2 gc = random(i + c);
	vec2 gd = random(i + d);

	//random values by random gradients
	float va = dot(ga, f - a);
	float vb = dot(gb, f - b);
	float vc = dot(gc, f - c);
	float vd = dot(gd, f - d);

	//mix(mix(va, vb, u.x), mix(vc, vd, u.x), u.y);
	float value = va + u.x * (vb - va) + u.y * (vc - va) + u.x * u.y * (va - vb - vc + vd);

	vec2 vb_vc; vb_vc.x = vb; vb_vc.y = vc;
	//mix(mix(ga, gb, u.x), mix(gc, gd, u.x), u.y);
	vec2 u_yx; u_yx.y = u.x; u_yx.x = u.y;
	vec2 derivatives = ga + (gb - ga) * u.x  + (gc - ga) * u.y  + (ga - gb - gc + gd) * u.x * u.y + du * (u_yx * (va - vb - vc + vd) + vb_vc - va);

	if (revert) value = 1.0 - 2.0 * value;

	vec3 R;
	R.x = value;
	R.y = derivatives.x;
	R.z = derivatives.y;
	return R;
}


/*vec3 f_noise3D(vec3 uv) {
	vec3 i = floor(uv);
	vec3 f = fract(uv);

	vec3 u = f*f*(3.0f-2.0f*f);
	

	vec3 v0; v0.x = 0; v0.y = 0; v0.y = 0;
	vec3 vx; vx.x = 1; vx.y = 0; vx.z = 0;

	vec3 vy; vy.x = 0; v0.y = 1; v0.y = 0;
	vec3 vz; vz.x = 0; vz.y = 0; vz.z = 1;
	vec3 vxy; vxy.x = 1; vxy.y = 1; vxy.z = 1;
	vec3 vxyz; vxyz.x = 1; vxyz.y = 1; vxyz.z = 1;


	vec3 t = mix(
		mix(dot(random(i + v0), f - v0), dot(random(i + vx), f - vx), u.x), 
		mix(dot(random(i + vx), f - vx), dot(random(i + vxy), f - vxy), u.y), 
		mix(dot(random(i + vz), f - vz), dot(random(i + vxyz), f - vxyz), u.z)
	);

	return t;
}*/




#undef in
#undef out

#endif //NOISE






